/* 
 *  Qactus - A Qt based OBS notifier
 *
 *  Copyright (C) 2010-2011 Sivan Greenberg <sivan@omniqueue.com>
 *  Copyright (C) 2010-2011 Javier Llorente <javier@opensuse.org>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 2 of the License, or
 *  (at your option) version 3.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "trayicon.h"
#include "xmlreader.h"
#include "configure.h"
#include "login.h"


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    manager = NULL;

    createToolbars();
    trayIcon = new TrayIcon;
    createActions();
    stream = new xmlReader;
    createTable();
    createTableRequests();
    createStatusBar();
    readSettings();

   loginDialog = new Login;
   configureDialog = new Configure;

    connect(configureDialog->timer, SIGNAL(timeout()), this, SLOT(refreshView()));

    connect(loginDialog->ui->pushButton_Login, SIGNAL(clicked()), this, SLOT(pushButton_Login_clicked()));
    connect(loginDialog->ui->lineEdit_Password, SIGNAL(returnPressed()), this, SLOT(lineEdit_Password_returnPressed()));

    connect(trayIcon->ourTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayIconClicked(QSystemTrayIcon::ActivationReason)));

}

MainWindow::~MainWindow()
{
    writeSettings();
    delete ui;
}

void MainWindow::changeEvent(QEvent *e)
{
    QMainWindow::changeEvent(e);
    switch (e->type()) {
    case QEvent::LanguageChange:
        ui->retranslateUi(this);
        break;
    default:
        break;
    }
}

void MainWindow::createManager()
{
    manager = new QNetworkAccessManager();
    connect(manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
    SLOT(provideAuthentication(QNetworkReply*,QAuthenticator*)));
    connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(httpReply(QNetworkReply*)));
    connect(manager, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError> &)), this, SLOT(onSslErrors(QNetworkReply*, const QList<QSslError> &)));
}

void MainWindow::makeRequest(QUrl url)
{
    QByteArray version(appVersion().toAscii());

    QNetworkRequest req(url);
    req.setRawHeader("User-Agent",version);
    manager->get(req);

    //    Don't make a new request until we get a reply
    QEventLoop *loop = new QEventLoop;
    connect(manager, SIGNAL(finished(QNetworkReply *)),loop, SLOT(quit()));
    loop->exec();
}

void MainWindow::onSslErrors(QNetworkReply* reply, const QList<QSslError> &list)
{
    QString errorString;

    foreach (const QSslError &error, list)
    {
        if (list.count() >= 1)
        {
            errorString += ", ";
            errorString = error.errorString();
        }
    }
    qDebug() << "SSL Errors:" << errorString;

    QString message;

    if(list.count() == 1)
    {
        message=tr("An SSL error has occured: %1");
    }
    else
    {
        message=list.count()+tr(" SSL errors have occured: %1");
    }

    if (QMessageBox::warning(this,tr("Warning"),
                             message.arg(errorString),
                             QMessageBox::Ignore | QMessageBox::Abort) == QMessageBox::Ignore)
    {
//        Ignore SSL error(s) if the user presses ignore
        reply->ignoreSslErrors();
    }

}

void MainWindow::provideAuthentication(QNetworkReply *reply, QAuthenticator *ator)
{
    static QString prevPassword = "";
    static QString prevUsername = "";
    qDebug() << reply->readAll();
    
    if ( reply->error() != QNetworkReply::NoError )
    {
            qDebug() << "------ Request failed: " << reply->errorString();
            statusBar()->showMessage(tr("Connection failed"), 0);
    }
    else
    {
        curPassword = QString(loginDialog->ui->lineEdit_Password->text());
        curUsername = QString(loginDialog->ui->lineEdit_Username->text());
        if ((curPassword != prevPassword) || (curUsername != prevUsername))
        {
            prevPassword = curPassword;
            prevUsername = curUsername;
            ator->setUser(curUsername);
            ator->setPassword(curPassword);
            statusBar()->showMessage(tr("Authenticating..."), 5000);
        }
        else
        {
            QMessageBox::warning(this,tr("Authentication Failed"), tr("The current authentication credentials failed to authenticate. <br>"
                                                      "Please make sure they are correct and try again."), QMessageBox::Ok );
            prevPassword = "";
            prevUsername = "";

            loginDialog->show();

        }
    }

}

void MainWindow::httpReply(QNetworkReply *reply)
{
      // QNetworkReply is a sequential-access QIODevice, which means that
      // once data is read from the object, it no longer kept by the device.
      // It is therefore the application's responsibility to keep this data if it needs to.
      // See http://doc.qt.nokia.com/latest/qnetworkreply.html for more info

    data = (QString) reply->readAll();

    qDebug () << "reply" << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();

    qDebug() << "networkreply: " << data;

//    Process data only if it contains package and status
    if(data.contains("package") && data.contains("status"))
    {
//    Read the XML
    stream->read(data,details);

//    Insert the data
    insertData(data,details);
    }

    if(data.contains("action"))
    {
//    Read the XML
      stream->readSR(data);

//    Insert the data
      insertRequests();
    }

    if (reply->error() != QNetworkReply::NoError)
    {
        packageErrors += reply->errorString() + "\n\n";
        qDebug() << "Request failed, " << packageErrors;
//        QMessageBox::critical(this,tr("Error"), tr("An error has occured:\n") + reply->errorString(), QMessageBox::Ok );
//        statusBar()->showMessage(tr("Error ") + reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toString(), 500000);
        return;
    }
    else
    {
        qDebug() << "Request succeeded!";
        statusBar()->showMessage(tr("Ready"), 0);
        action_Refresh->setEnabled(true);
        action_Timer->setEnabled(true);
        return;
    }

}

void MainWindow::createToolbars()
{
    action_Add = new QAction(tr("&Add"), this);
    action_Add->setIcon(QIcon("icons/list-add.png"));
    action_Add->setStatusTip(tr("Add a new row"));
    ui->toolBar->addAction(action_Add);
    connect(action_Add, SIGNAL(triggered()), this, SLOT(addRow()));

    action_Remove = new QAction(tr("&Remove"), this);
    action_Remove->setIcon(QIcon("icons/list-remove.png"));
    action_Remove->setStatusTip(tr("Remove selected row"));
    ui->toolBar->addAction(action_Remove);
    connect(action_Remove, SIGNAL(triggered()), this, SLOT(removeRow()));

    action_Refresh = new QAction(tr("&Refresh"), this);
    action_Refresh->setIcon(QIcon("icons/view-refresh.png"));
    action_Refresh->setStatusTip(tr("Refresh view"));
    action_Refresh->setEnabled(false);
    ui->toolBar->addAction(action_Refresh);
    connect(action_Refresh, SIGNAL(triggered()), this, SLOT(refreshView()));

    ui->toolBar->addSeparator();

    action_Timer = new QAction(tr("&Timer"), this);
    action_Timer->setIcon(QIcon("icons/chronometer.png"));
    action_Timer->setStatusTip(tr("Timer"));
    action_Timer->setEnabled(false);
    ui->toolBar->addAction(action_Timer);
    connect(action_Timer, SIGNAL(triggered()), this, SLOT(on_actionConfigure_Qactus_triggered()));

}

void MainWindow::addRow()
{
//    Append a row
    int row=ui->table->rowCount();
    ui->table->insertRow(row);
//    Append an empty statusList
    statusList.insert(row,"");
    qDebug() << "Row appended at: " << row;
}

void MainWindow::removeRow()
{
//    Check if the table is not empty
    if(ui->table->rowCount()!=0)
    {
//    Remove selected row
    int row = ui->table->currentRow();

//    Remove statusList for selected row
//    -1 means that there is no row selected
        if(row!=-1)
        {
            ui->table->removeRow(row);
            statusList.removeAt(row);
            qDebug() << "Row removed: " << row;
        }
        else
        {
            qDebug () << "No row selected";
        }
    }
    else
    {
//        If the table is empty, do nothing
    }
    
}

void MainWindow::refreshView()
{
    int rows=ui->table->rowCount();

    for(r=0; r<rows; r++)
        {
            if (!ui->table->item(r,0)||!ui->table->item(r,1)||!ui->table->item(r,2)||!ui->table->item(r,3))
            {
//                Ignore rows with empty fields
//                (and process rows with data)
            }
            else
            {
                qDebug() << "Refreshing view...";

//                URL format: https://api.opensuse.org/build/KDE:Release:45/openSUSE_11.3/x86_64/ktorrent/_status
                QUrl url = "https://api.opensuse.org/build/" + QString(ui->table->item(r,0)->text()) + "/" + QString(ui->table->item(r,2)->text()) + "/" + QString(ui->table->item(r,3)->text()) + "/" + QString(ui->table->item(r,1)->text()) + "/_status";

                makeRequest(url);
            }
        }

    if(packageErrors.size()>1)
    {
        QMessageBox::critical(this,tr("Error"), packageErrors, QMessageBox::Ok );
        packageErrors.clear();
    }

    // Get SRs
    getRequests();

}

void MainWindow::createTable()
{
    ui->table->setColumnCount(5);
    ui->table->setColumnWidth(0, 150); // Project
    ui->table->setColumnWidth(1, 150); // Package
    ui->table->setColumnWidth(2, 115); // Repository
    ui->table->setColumnWidth(3, 75); // Arch
    ui->table->setColumnWidth(4, 140); // Status

//    connect(ui->table,SIGNAL(cellChanged(int,int)), this, SLOT(on_cellChanged()));

}

void MainWindow::createTableRequests()
{
    ui->tableRequests->setColumnCount(7);

    ui->tableRequests->setColumnWidth(0, 90); // Date
    ui->tableRequests->setColumnWidth(1, 60); // SR ID
    ui->tableRequests->setColumnWidth(2, 160); // Source project
    ui->tableRequests->setColumnWidth(3, 160); // Target project
    ui->tableRequests->setColumnWidth(4, 90); // Requester
    ui->tableRequests->setColumnWidth(5, 60); // Type
    ui->tableRequests->setColumnWidth(6, 60); // State

}

void MainWindow::insertData(const QString& status, QString& details)
{
    newItem = new QTableWidgetItem();
    newItem->setText(status);


//    If the line is too long, break it
    int i=250;
    if(details.size()>i)
    {
        for(; i<details.size(); i++)
        {
            if(details[i]==QChar(',')||details[i]==QChar('-')||details[i]==QChar(' '))
                {
                details.insert(++i,QString("<br>"));
                break;
                }
        }
    }
    qDebug() << "string size: " << details.size();

    newItem->setToolTip(details);

    ui->table->setItem(r, 4, newItem);
    qDebug() << "status" << status << "inserted in" << r;
    qDebug() << "rows: " << ui->table->rowCount();

//    If the statusList is not empty and the status is different from last time, change the icon
    if(statusList.at(r)!=""&&status!=statusList.at(r))
    {
        qDebug() << "Status changed!" << status << statusList.at(r) << " row: " << r;
        trayIcon->change();
    }
    qDebug() << "change?" << status << statusList.at(r) << " row: " << r;
    qDebug() << "size: " << statusList.size();

//    Insert the last status into statusList
    statusList[r] = status;

//    Set the status cell to non-editable
    newItem->setFlags(Qt::ItemIsEditable);

//    Change the status' colour according to the status itself
    if(status=="succeeded")
    {
        newItem->setForeground(Qt::darkGreen);
    }
    else if(status=="blocked")
    {
        newItem->setForeground(Qt::gray);
    }
    else if(status=="scheduled"||status=="building")
    {
        newItem->setForeground(Qt::darkBlue);
    }
    else if(status=="failed")
    {
        newItem->setForeground(Qt::red);
    }
    else if(status=="unresolvable")
    {
        newItem->setForeground(Qt::darkRed);
    }

}

void MainWindow::insertRequests()
{
//    If we already have inserted submit requests,
//    we remove them and insert the latest ones

    int rows = ui->tableRequests->rowCount();
    int requests = stream->reqNumber.toInt();
    qDebug () << "Rows:" << rows;
    qDebug() << "Requests:" << requests;

    if(rows!=0)
    {
        for(int i=requests-1; i!=-1; i--)
        {
            qDebug () << "Removing row at:" << i;
            ui->tableRequests->removeRow(i);
        }
    }

    for (int i=0; i<stream->reqNumber.toInt(); i++)
    {
        ui->tableRequests->insertRow(i);

        reqDataItem = new QTableWidgetItem();
        reqDataItem->setText(stream->reqDate.at(i));
        ui->tableRequests->setItem(i, 0, reqDataItem);
        reqDataItem->setFlags(Qt::ItemIsEditable);
        reqDataItem->setForeground(Qt::black);

        reqIDItem = new QTableWidgetItem();
        reqIDItem->setText(stream->reqID.at(i));
        ui->tableRequests->setItem(i, 1, reqIDItem);
        reqIDItem->setFlags(Qt::ItemIsEditable);
        reqIDItem->setForeground(Qt::black);

        reqSourceProjectItem = new QTableWidgetItem();
        reqSourceProjectItem->setText(stream->reqSourceProject.at(i));
        ui->tableRequests->setItem(i, 2, reqSourceProjectItem);
        reqSourceProjectItem->setFlags(Qt::ItemIsEditable);
        reqSourceProjectItem->setForeground(Qt::black);

        reqTargetProjectItem = new QTableWidgetItem();
        reqTargetProjectItem->setText(stream->reqTargetProject.at(i));
        ui->tableRequests->setItem(i, 3, reqTargetProjectItem);
        reqTargetProjectItem->setFlags(Qt::ItemIsEditable);
        reqTargetProjectItem->setForeground(Qt::black);

        requesterItem = new QTableWidgetItem();
        requesterItem->setText(stream->requester.at(i));
        ui->tableRequests->setItem(i, 4, requesterItem);
        requesterItem->setFlags(Qt::ItemIsEditable);
        requesterItem->setForeground(Qt::black);

        reqTypeItem = new QTableWidgetItem();
        reqTypeItem->setText(stream->reqType.at(i));
        ui->tableRequests->setItem(i, 5, reqTypeItem);
        reqTypeItem->setFlags(Qt::ItemIsEditable);
        reqTypeItem->setForeground(Qt::black);

        reqStateItem = new QTableWidgetItem();
        reqStateItem->setText(stream->reqState.at(i));
        ui->tableRequests->setItem(i, 6, reqStateItem);
        reqStateItem->setFlags(Qt::ItemIsEditable);
        reqStateItem->setForeground(Qt::black);
    }
}

void MainWindow::pushButton_Login_clicked()
{
////    Allow login with another username/password
    delete manager;

    createManager();

//    Display a warning if the username/password is empty.
    if(loginDialog->ui->lineEdit_Username->text()==""||loginDialog->ui->lineEdit_Password->text()=="")
    {
        QMessageBox::warning(this,tr("Error"), tr("Empty username/password"), QMessageBox::Ok );
    }
    else
    {
        loginDialog->close();

        QUrl url("https://api.opensuse.org");
        makeRequest(url);
    }
}

void MainWindow::lineEdit_Password_returnPressed()
{
    pushButton_Login_clicked();
}

void MainWindow::on_actionQuit_triggered(bool)
{
    close();
}

void MainWindow::on_actionAbout_triggered(bool)
{
    about();
}

//void MainWindow::on_cellChanged()
//{
//    Not working properly
//    if(ui->table->currentColumn()==3)
//    {
//        if (!ui->table->item(r,0)||!ui->table->item(r,1)||!ui->table->item(r,2)||!ui->table->item(r,3))
//        {
////                Ignore rows with empty fields
////                (and process rows with data)
//        }
//        else
//        {
//            qDebug() << "Refreshing view...";
//
//            r=ui->table->currentRow();
//
////                URL format: https://api.opensuse.org/build/KDE:Release:45/openSUSE_11.3/x86_64/ktorrent/_status
//            QUrl url = "https://api.opensuse.org/build/" + QString(ui->table->item(r,0)->text()) + "/" + QString(ui->table->item(r,2)->text()) + "/" + QString(ui->table->item(r,3)->text()) + "/" + QString(ui->table->item(r,1)->text()) + "/_status";
//
//            makeRequest(url);
//        }
//    }
//}


void MainWindow::about()
{
    QMessageBox::about(this,tr("About Qactus"),
                       tr("<h2 align=\"left\">Qactus</h2>")
                       + "Qactus is a Qt-based OBS notifier<br>"
                       + tr("Version: ") + appVersion() +
                       tr("<div align=\"left\">"
                          "<p>"
                          "<b>Authors:</b> <br>"
                          "Sivan Greenberg<br>"
                          "sivan@omniqueue.com<br><br>"
                          "Javier Llorente<br>"
                          "javier@opensuse.org<br><br>"
                          "<b>Artwork:</b> <br>"
                          "Icons by the Oxygen Team<br>"
                          "<a href=\"http://www.oxygen-icons.org/\">http://www.oxygen-icons.org/</a><br><br>"
                          "Tray icon by the Open Build Service<br>"
                          "<a href=\"http://openbuildservice.org/\">http://openbuildservice.org/</a>"
                          "</p>"
                          "<p>"
                          "<b>License:</b> <br>"
                          "<nobr>This program is under GNU General Public License v3</nobr>"
                          "</p>"
                          "</div>")
                       );
}

void MainWindow::createActions()
{
    action_aboutQt = new QAction(tr("About &Qt"), this);
    connect(ui->action_aboutQt, SIGNAL(triggered()), qApp, SLOT(aboutQt()));

//    action_Configure = new QAction(tr("&Configure"), trayIcon);
//    action_Configure->setIcon(QIcon("icons/configure.png"));
//    connect(action_Configure, SIGNAL(triggered()), this, SLOT(on_actionConfigure_Qactus_triggered()));
//    trayIcon->trayIconMenu->addAction(action_Configure);

    trayIcon->trayIconMenu->addSeparator();

    action_Restore = new QAction(tr("&Minimise"), trayIcon);
    connect(action_Restore, SIGNAL(triggered()), this, SLOT(toggleVisibility()));
    trayIcon->trayIconMenu->addAction(action_Restore);

    action_Quit = new QAction(tr("&Quit"), trayIcon);
    action_Quit->setIcon(QIcon("icons/application-exit.png"));
    connect(action_Quit, SIGNAL(triggered()), qApp, SLOT(quit()));
    trayIcon->trayIconMenu->addAction(action_Quit);
}

void MainWindow::createStatusBar()
{
    statusBar()->showMessage(tr("Offline"));
}

void MainWindow::toggleVisibility()
{
    if(this->isVisible())
    {
        hide();
        action_Restore->setText(tr("Restore"));
    }
    else
    {
        showNormal();
        action_Restore->setText(tr("Minimise"));
    }
}

void MainWindow::trayIconClicked(QSystemTrayIcon::ActivationReason reason)
{
    if(reason==QSystemTrayIcon::Trigger)
    {
        toggleVisibility();
    }
}

void MainWindow::writeSettings()
{
    QSettings settings("Qactus","Qactus");
    settings.beginGroup("MainWindow");
    settings.setValue("pos", pos());
    settings.endGroup();

    int rows=ui->table->rowCount();
    settings.beginWriteArray("Packages");
    for (r= 0; r<rows; ++r)
    {
        settings.setArrayIndex(r);
//        Save settings only if all the cells in a row r have text
        if(ui->table->item(r,0)&&ui->table->item(r,1)&&ui->table->item(r,2)&&ui->table->item(r,3))
        {
            settings.setValue("Project",ui->table->item(r, 0)->text());
            settings.setValue("Package",ui->table->item(r, 1)->text());
            settings.setValue("Repository",ui->table->item(r, 2)->text());
            settings.setValue("Arch",ui->table->item(r, 3)->text());
        }
    }
    settings.endArray();
}

void MainWindow::readSettings()
{
    QSettings settings("Qactus","Qactus");
    settings.beginGroup("MainWindow");
    move(settings.value("pos", QPoint(200, 200)).toPoint());
    settings.endGroup();

    int size = settings.beginReadArray("Packages");
    for (r=0; r<size; ++r)
        {
            settings.setArrayIndex(r);
            addRow();

            QTableWidgetItem *project = new QTableWidgetItem;
            project->setText(settings.value("Project").toString());
            ui->table->setItem(r, 0, project);

            QTableWidgetItem *package = new QTableWidgetItem;
            package->setText(settings.value("Package").toString());
            ui->table->setItem(r, 1, package);

            QTableWidgetItem *repository = new QTableWidgetItem;
            repository->setText(settings.value("Repository").toString());
            ui->table->setItem(r, 2, repository);

            QTableWidgetItem *arch = new QTableWidgetItem;
            arch->setText(settings.value("Arch").toString());
            ui->table->setItem(r, 3, arch);
        }
        settings.endArray();

}

void MainWindow::on_actionConfigure_Qactus_triggered()
{
    configureDialog->show();
}

void MainWindow::on_actionLogin_triggered()
{
    loginDialog->show();
}

void MainWindow::getRequests()
{
//    QUrl url("https://api.opensuse.org/request?view=collection&states=new&roles=maintainer&user=someusername");
    QUrl url = "https://api.opensuse.org/request?view=collection&states=new&roles=maintainer&user=" + curUsername;
    makeRequest(url);

}

void MainWindow::on_tabWidget_currentChanged(int index)
{
    // Disable add and remove for the request tab
    action_Add->setEnabled(!index);
    action_Remove->setEnabled(!index);
}

QString MainWindow::appVersion()
{
//    Returns Qactus version
    return "0.1.1";
}
